package cn.openea.perpartner.meily.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.openea.perpartner.common.core.constant.DateConstant;
import cn.openea.perpartner.common.core.exception.ServiceException;
import cn.openea.perpartner.common.core.utils.DateUtils;
import cn.openea.perpartner.common.core.utils.IdWorker;
import cn.openea.perpartner.common.core.utils.poi.ExcelUtil;
import cn.openea.perpartner.common.core.web.domain.AjaxResult;
import cn.openea.perpartner.meily.constant.CommonConstants;
import cn.openea.perpartner.meily.constant.enums.AssessmentLevelEnums;
import cn.openea.perpartner.meily.constant.enums.NotifySceneEnum;
import cn.openea.perpartner.meily.constant.enums.NotifySendEnum;
import cn.openea.perpartner.meily.thirdparty.WxPaySystemApi;
import cn.openea.perpartner.meily.thirdparty.notify.NotifySendEvent;
import cn.openea.perpartner.meily.util.CosUpload;
import cn.openea.perpartner.meily.web.entity.*;
import cn.openea.perpartner.meily.web.entity.dto.MaterialDownloadDTO;
import cn.openea.perpartner.meily.web.entity.dto.ProvideSamplesSubDTOFactory;
import cn.openea.perpartner.meily.web.entity.vo.GoodsDeliveryNoticeVo;
import cn.openea.perpartner.meily.web.entity.vo.ProvideSamplesSubVo;
import cn.openea.perpartner.meily.web.mapper.ProvideSamplesSubMapper;
import cn.openea.perpartner.meily.web.service.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service("provideSamplesSubService")
public class ProvideSamplesSubServiceImpl extends ServiceImpl<ProvideSamplesSubMapper, ProvideSamplesSub> implements IProvideSamplesSubService {

    @Resource
    private IProvideSamplesService provideSamplesService;
    @Resource
    private IProviderService providerService;
    @Resource
    private IPersonalInfoService personalInfoService;
    @Resource
    private IBlackListService blackListService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private ProvideSamplesSubDTOFactory provideSamplesSubDTOFactory;
    @Resource
    private CosUpload cosUpload;
    @Resource
    private WxPaySystemApi wxPaySystemApi;

    @Value("${bpm.rest.url}")
    private String bpmUrl;
    @Value("${meily.header.sysid}")
    private String sysId;
    @Value("${meily.header.syspwd}")
    private String sysPwd;
    @Value("${bpm.msg_appid}")
    private String msgAppid;
    @Value("${bpm.msg_wf_num}")
    private String msgWfNum;
    @Value("${payment.order.authSalt}")
    private String authSalt;
    @Value("${payment.order.subPayToWallet}")
    private String subPayToWallet;
    @Value("${integral_sysytem_id}")
    private String INTEGRAL_SYSTEM_ID;
    @Value("${payment.order.getTokenUrl}")
    private String getOrderSysTokenUrl;
    @Value("${payment.order.addOrderUrl}")
    private String addOrderUrl;
    @Value("${payment.coupon.createAndIssueUrl}")
    private String createAndIssueUrl;
    @Value("${payment.order.deductUrl}")
    private String deductUrl;

    private IdWorker worker = new IdWorker(1, 1, 1);

    /**
     * 校验是否可以报名
     * 返回的code值说明：
     * （1）200：可以报名
     * （2）202：无名额
     * （3）203：已报名，并返回跳转路径
     * （4）204：不可报名（活动结束等）
     * （5）205：测评师资料尚未填写完毕
     * （6）206：无权限
     * （7）207：未注册“区域服务商”
     * <p>
     * 注意：校验顺序不随意调整，除非业务上有调整！！！！！
     */
    @Override
    public JSONObject verifyRegistration(ProvideSamplesSub samplesSub) {

        JSONObject object = new JSONObject();
        object.put("code", 201);
        object.put("msg", "-未知错误-");

        // 发起人id
        String initiatorId = samplesSub.getInitiatorId();

        // 参与者id
        String partnerId = samplesSub.getPartnerId();

        // 报名用户的等级
        String grade = "";

        /**
         * 第1步 判断是否符合领取条件
         */
        // 1.判断样品发放记录是否存在
        ProvideSamples provideSamples = provideSamplesService.getById(samplesSub.getMainId());
        if (provideSamples == null) {
            object.put("code", 204);
            object.put("msg", "样品不存在！");
            return object;
        }

        // 1.1 活动已结束
        // 任务状态。0:正常结束(到期自动结束)；1:正在进行中；2:报名结束；3:活动作废(手动结束)
        if ("0".equals(provideSamples.getStatus())) {
            object.put("code", 204);
            object.put("msg", "此次样品发放活动已结束！");
            return object;
        } else if ("2".equals(provideSamples.getStatus())) {
            object.put("code", 204);
            object.put("msg", "此次活动已提前结束！");
            return object;
        } else if ("3".equals(provideSamples.getStatus())) {
            object.put("code", 204);
            object.put("msg", "此次活动已作废！");
            return object;
        }

        // 2.校验报名截止时间
        LocalDate now = LocalDate.now();
        LocalDate joinEndTime = DateUtils.formatLocalDate(provideSamples.getJoinEndTime() + " 00:00:00", DateConstant.DEFAULT_DATE_TIME_PATTERN);
        if (joinEndTime.compareTo(now) < 0) {
            object.put("code", 204);
            object.put("msg", "已超过样品领取时间，不可领取！");
            return object;
        }

        // 3.校验结束时间
        LocalDate endTime = DateUtils.formatLocalDate(provideSamples.getEndTime() + " 00:00:00", DateConstant.DEFAULT_DATE_TIME_PATTERN);
        if (endTime.compareTo(now) < 0) {
            throw new ServiceException("此次样品发放活动已结束！", 204);
        }

        /**
         * 4.如未提交反馈的领取记录，不可报名下一个样品活动
         */
        Long count1 = baseMapper.selectCount(new LambdaQueryWrapper<ProvideSamplesSub>()
                .eq(ProvideSamplesSub::getPartnerId, partnerId)
                .eq(ProvideSamplesSub::getOrderStatus, "已完成"));
        if (count1 > 0) {
            object.put("code", 208);
            object.put("msg", "您有未反馈的订单，完成后即可报名！");
            return object;
        }

        // 5.发起人不可领取
        if (partnerId.equals(initiatorId)) {
            object.put("code", 204);
            object.put("msg", "您不能领取自己发起的样品！");
            return object;
        }

        // 6.报名限制周期内参与过样品发放活动就提示无名额
        if (provideSamples.getJoinLimitDays() > 0) {
            QueryWrapper<ProvideSamplesSub> wrapper = new QueryWrapper<>();
            StringBuffer queryStr = new StringBuffer();
            if (StrUtil.isNotBlank(samplesSub.getPartnerId())) {
                queryStr.append(" and partner_id = '" + samplesSub.getPartnerId() + "'");
            }
            queryStr.append(" and order_status <> '待支付' ");
            queryStr.append(" and date_sub(CURDATE(), interval " + provideSamples.getJoinLimitDays() + " day) <= date(create_time)");
            wrapper.last(" " + queryStr + " ");
            long totalNum = baseMapper.getDuringRecordNum(wrapper);

            if (totalNum > 0) {
                object.put("code", 202);
                object.put("msg", "很抱歉！每位区域服务商" + provideSamples.getJoinLimitDays() + "天内只有1次领取资格哦～！");
                return object;
            }
        }

        // 7.判断是否已领取，若已领取，则不可再次领取；
        Long count = baseMapper.selectCount(new LambdaQueryWrapper<ProvideSamplesSub>()
                .eq(ProvideSamplesSub::getPartnerId, partnerId)
                .eq(ProvideSamplesSub::getMainId, provideSamples.getId())
                .ne(ProvideSamplesSub::getOrderStatus, "待支付"));// 不查询待支付的记录
        if (count > 0) {
            object.put("code", 204);
            object.put("msg", "您已经领取过此样品，不可重复领取！");
            return object;
        }

        /**
         * 12.判断是否已存在“待支付”的记录，若存在，则表示此参与者之前已经通过报名校验并且锁定名额，可以报名
         */
        LambdaQueryWrapper<ProvideSamplesSub> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProvideSamplesSub::getMainId, samplesSub.getMainId());
        queryWrapper.eq(ProvideSamplesSub::getPartnerId, samplesSub.getPartnerId());
        queryWrapper.eq(ProvideSamplesSub::getOrderStatus, "待支付");
        ProvideSamplesSub oldSub = getOne(queryWrapper);
        if (oldSub != null) {
            object.put("code", 200);
            object.put("msg", "可以报名！");
            return object;
        }

        // 8.判断样品领取人数是否还有剩余
        Long quota = baseMapper.selectCount(new LambdaQueryWrapper<ProvideSamplesSub>()
                .eq(ProvideSamplesSub::getMainId, provideSamples.getId())
                .ne(ProvideSamplesSub::getOrderStatus, "已回收"));
        if (quota >= provideSamples.getSampleQuota()) {
            object.put("code", 202);
            object.put("msg", "此样品已全部发放完成，无领取名额！");
            return object;
        }

        // 9.活动面向群体。0:测评师；1:区域服务商
        if ("0".equals(provideSamples.getEventParticipants())) {
            // 测评师
            PersonalInfo personalInfo = personalInfoService.selectByUserId(partnerId);
            if (personalInfo == null) {
                object.put("code", 205);
                object.put("msg", "测评师资料尚未填写完毕，不可领取，是否前往填写！");
                return object;
            }
            grade = personalInfo.getEvaluationGrade();

            if (!personalInfoService.checkEvaluatorInfoFinish(partnerId)) {
                object.put("code", 205);
                object.put("msg", "测评师资料尚未填写完毕，不可领取，是否前往填写！");
                return object;

            }
        } else if ("1".equals(provideSamples.getEventParticipants())) {
            // 区域服务商
            Provider provider = providerService.getByUserId(partnerId);
            if (provider == null) {
                object.put("code", 207);
                object.put("msg", "未注册“区域服务商”，不可领取！");
                return object;
            }
            grade = provider.getGrade();
        }

        // 10.判断等级
        if (StringUtils.isNotBlank(provideSamples.getRestrictionLevel()) && !AssessmentLevelEnums.compareGrades(provideSamples.getRestrictionLevel(), grade)) {
            object.put("code", 204);
            object.put("msg", "很抱歉！您的等级不满足领取要求，不可领取！");
            return object;
        }

        // 11.判断黑名单
        BlackList blackList = blackListService.selectOneByUserId(partnerId);
        if (blackList != null) {
            object.put("code", 206);
            object.put("msg", "很抱歉！你暂无领取权限，请联系客服！");
            return object;
        }

        object.put("code", 200);
        object.put("msg", "可以报名！");
        return object;
    }

    /**
     * 锁定名额
     * 步骤：
     * 1.判断是否符合领取条件；
     * 2.保存领取记录(orderStatus == "待支付")
     * 3.更新样品剩余数量
     *
     * @param samplesSub
     */
    @Override
    public AjaxResult lockedQuota(ProvideSamplesSub samplesSub) {

        /**
         * 第1步 判断是否符合领取条件
         */
        JSONObject object = verifyRegistration(samplesSub);
        if (object.getInteger("code") > 200) {
            throw new ServiceException(object.getString("msg"), object.getInteger("code"));
        }

        /**
         * 第2步 保存领取记录
         * 先查询，是否已经存在未支付的记录，如果有直接返回。否则生成新记录
         */
        LambdaQueryWrapper<ProvideSamplesSub> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProvideSamplesSub::getMainId, samplesSub.getMainId());
        queryWrapper.eq(ProvideSamplesSub::getPartnerId, samplesSub.getPartnerId());
        queryWrapper.eq(ProvideSamplesSub::getOrderStatus, "待支付");
        ProvideSamplesSub oldSub = getOne(queryWrapper);
        if (oldSub != null) {
            return AjaxResult.success("锁定名额成功，可以领取！", oldSub);
        }

        samplesSub.setTaskNumber(String.valueOf(worker.nextId()));// 任务单号，全使用数字
        samplesSub.setOrderStatus("待支付");
        samplesSub.setConsigneeAddress("");// 需要将收货地址设为空，不然可能会出现地址数据不完整，导致无法加载数据 2023-07-10 add by lys
        if (baseMapper.insert(samplesSub) != 1) {
            throw new ServiceException("锁定名额出错了！");
        }

        /**
         * 第3步 更新样品剩余数量
         */
        ProvideSamples provideSamples = provideSamplesService.getById(samplesSub.getMainId());
        if (provideSamples != null) {
            LambdaUpdateWrapper<ProvideSamples> updateWrapper = new LambdaUpdateWrapper();
            updateWrapper.eq(ProvideSamples::getId, samplesSub.getMainId());
            updateWrapper.set(ProvideSamples::getRemainQuota, provideSamples.getRemainQuota() - 1);// 剩余名额
            updateWrapper.set(ProvideSamples::getJoinNum, provideSamples.getJoinNum() + 1);// 参与人数
            updateWrapper.set(ProvideSamples::getUpdateTime, DateUtil.now());
            if (!provideSamplesService.update(updateWrapper)) {
                throw new ServiceException("更新剩余名额出错了！");
            }
        }

        return AjaxResult.success("锁定名额成功，可以领取！", samplesSub);
    }

    /**
     * 领取样品
     * 步骤：
     * 1.判断是否可以领取样品
     * 2.保存领取记录；
     * 3.保存记录到订单系统；
     * 4.使用钱包余额进行抵扣(2023-06-15 add);
     * 4.更新样品发放数据；
     * 5.给参与者发送订单通知；
     * 6.修改需求大厅表数据（暂不处理）；
     *
     * @param samplesSub
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receiveProvideSamples(ProvideSamplesSub samplesSub) {

        /**
         * 第1步 判断是否符合领取条件
         */
        JSONObject object = verifyRegistration(samplesSub);
        if (object.getInteger("code") > 200) {
            throw new ServiceException(object.getString("msg"), object.getInteger("code"));
        }

        // 1.判断样品发放记录是否存在
        ProvideSamples provideSamples = Optional.ofNullable(provideSamplesService.getById(samplesSub.getMainId()))
                .orElseThrow(() -> new ServiceException("样品不存在"));

        // 判断是否存在“锁定名额”记录，不存在则需要重新校验是否还有名额
        if (getById(samplesSub.getId()) == null) {
            // 2.判断样品领取人数是否还有剩余
            Long quota = baseMapper.selectCount(new LambdaQueryWrapper<ProvideSamplesSub>()
                    .eq(ProvideSamplesSub::getMainId, provideSamples.getId())
                    .ne(ProvideSamplesSub::getOrderStatus, "已回收"));
            if (quota >= provideSamples.getSampleQuota()) {
                throw new ServiceException("此样品已全部发放完成，无领取名额", 202);
            }
        }

        /**
         * 第2步 保存领取记录
         */
        samplesSub.setEnableFeedback(provideSamples.getEnableFeedback());// 是否开启反馈
        samplesSub.setTaskNumber(String.valueOf(worker.nextId()));// 任务单号，全使用数字
        samplesSub.setOrderStatus("待发货");
        samplesSub.setUpdateTime(DateUtil.now());
        if (!saveOrUpdate(samplesSub)) {
            throw new ServiceException("保存领取记录失败！");
        }

        System.out.println("************实体对象*************");
        System.out.println("samplesSub=" + samplesSub);

        /**
         * 第2步 保存记录到订单系统
         */
        JSONObject orderObject = new JSONObject();
        orderObject.put("orderId", samplesSub.getOrderId());// 订单编号（meily_provide_samples_sub表中的order_id）
        orderObject.put("orderName", "购买" + samplesSub.getGoodsName());// 订单名称
        orderObject.put("orderStatus", "已支付");// 订单状态。0:待支付；1:已支付；2:支付取消；(默认0)
        orderObject.put("orderType", "领取样品");// 订单类型。
        orderObject.put("orderPrice", samplesSub.getPayAmount());// 订单金额
        orderObject.put("orderImages", samplesSub.getGoodsImages().split(",")[0]);// 订单图片
        orderObject.put("orderLink", "/pages_private_scene2/provide_samples/order_details?recordId=" + samplesSub.getId());// 订单详情地址
        orderObject.put("remark", "领取了1件样品");// 订单备注
        orderObject.put("sceneId", samplesSub.getSceneId());// 场景id
        orderObject.put("sourceId", samplesSub.getId());// 来源id（meily_provide_samples_sub表中的id）
        orderObject.put("createUser", samplesSub.getPartnerId());// 订单创建者id
        orderObject.put("createUserName", samplesSub.getPartnerName());// 订单创建者昵称
        orderObject.put("createUserAvatar", samplesSub.getPartnerAvatarUrl());// 订单创建者头像
        orderObject.put("sourceModule", "meily_provide_samples_sub");// 来源模块（数据表名）
        orderObject.put("useDeduction", samplesSub.getUseDeduction());// 是否使用抵扣
        orderObject.put("deductionAmount", samplesSub.getDeductionAmount());// 抵扣金额
        orderObject = getToken(orderObject);
        JSONObject resObj = saveRecord2OrderSys(orderObject);
        if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
            throw new ServiceException("保存记录到订单系统失败！");
        }

        /**
         * 2023-06-15 add
         * 第3步 使用钱包余额进行抵扣
         */
        if("1".equals(samplesSub.getUseDeduction()) && samplesSub.getDeductionAmount().compareTo(BigDecimal.ZERO) > 0){
            JSONObject object2 = new JSONObject();
            object2.put("userId", samplesSub.getPartnerId());// 用户id
            object2.put("coin", samplesSub.getDeductionAmount());// 扣减金额
            object2.put("reason", "领取" + samplesSub.getGoodsName() + "时，使用钱包余额进行抵扣");// 原因
            object2 = getToken(object2);
            JSONObject resObj2 = deduction(object2);
            if (resObj2.isEmpty() || !"200".equals(resObj2.getString("code"))) {
                throw new ServiceException("使用钱包余额进行抵扣：扣减钱包金额失败！");
            }
        }

        /**
         * 第4步 更新样品发放数据
         * 修改ProvideSamples：读者域、领取记录id、参与者id、参与者昵称
         */
        // 读者域
        String allReaders = "";
        if (StrUtil.isNotBlank(provideSamples.getAllReaders())) {
            HashSet<String> set = cn.openea.perpartner.common.core.utils.StringUtils.splitAsSet(provideSamples.getAllReaders());
            set.add(samplesSub.getPartnerId());
            allReaders = cn.openea.perpartner.common.core.utils.StringUtils.join(set, ",");
        } else {
            allReaders = samplesSub.getPartnerId();
        }

        // 领取记录id
        String allSubId = "";
        if (StrUtil.isNotBlank(provideSamples.getAllSubId())) {
            HashSet<String> set = cn.openea.perpartner.common.core.utils.StringUtils.splitAsSet(provideSamples.getAllSubId());
            set.add(samplesSub.getId());
            allSubId = cn.openea.perpartner.common.core.utils.StringUtils.join(set, ",");
        } else {
            allSubId = samplesSub.getId();
        }

        // 参与者id
        String joinMember = "";
        if (StrUtil.isNotBlank(provideSamples.getJoinMember())) {
            HashSet<String> set = cn.openea.perpartner.common.core.utils.StringUtils.splitAsSet(provideSamples.getJoinMember());
            set.add(samplesSub.getPartnerId());
            joinMember = cn.openea.perpartner.common.core.utils.StringUtils.join(set, ",");
        } else {
            joinMember = samplesSub.getPartnerId();
        }

        // 参与者昵称
        String joinMemberName = "";
        if (StrUtil.isNotBlank(provideSamples.getJoinMemberName())) {
            HashSet<String> set = cn.openea.perpartner.common.core.utils.StringUtils.splitAsSet(provideSamples.getJoinMemberName());
            set.add(samplesSub.getPartnerName());
            joinMemberName = cn.openea.perpartner.common.core.utils.StringUtils.join(set, ",");
        } else {
            joinMemberName = samplesSub.getPartnerName();
        }

        provideSamplesService.edit(ProvideSamples.builder()
                .id(provideSamples.getId())
                .allReaders(allReaders)
                .allSubId(allSubId)
                .joinMember(joinMember)
                .joinMemberName(joinMemberName)
                .build());

        /**
         * 第5步 给参与者发送订单通知
         */
        String first = "您已成功领取样品1份，平台将48小时内安排发货！如果对商品满意，欢迎代理销售赚取佣金哦！";
        // 选择活动群体是“区域服务商”
        if ("1".equals(provideSamples.getEventParticipants())) {
            // 获取当前用户的区域服务商信息
            Provider provider = providerService.getByUserId(samplesSub.getPartnerId());
            if (provider != null) {
                first = "【区域服务商NO." + provider.getProviderId() + "】您已成功领取样品1份，平台将48小时内安排发货！您所在区域发现不少潜在消费者，建议发起商品销售赚取佣金！";
            }
        }

        HashMap<String, Object> params = new HashMap<>();
        params.put("first", first);
        params.put("keyword1", samplesSub.getTaskNumber());// 订单编号
        params.put("keyword2", samplesSub.getGoodsName());// 商品名称
        params.put("remark", "点击查看订单详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
        params.put("pagepath", "/pages_private_scene2/provide_samples/order_details?recordId=" + samplesSub.getId());// 跳转到订单详情
        params.put("pageurl", "/pages_private_scene2/provide_samples/order_details?recordId=" + samplesSub.getId());// 跳转到订单详情
        params.put("docUnid", samplesSub.getId());
        params.put("userId", samplesSub.getPartnerId());
        Map<String, Object> data = new HashMap<>();
        data.put(NotifySendEnum.WX_PUBLIC_NUMBER.name(), params);
        applicationContext.publishEvent(new NotifySendEvent(this,
                NotifySendEnum.WX_PUBLIC_NUMBER,
                NotifySceneEnum.GOODS_DELIVERY,
                data));
    }

    /**
     * 回收名额
     * 步骤：
     * 1.修改领取记录状态为“已回收”；
     * 2.释放名额；
     * 3.给参与者发放回收名额通知；
     *
     * @param samplesSubVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult recyclingQuota(ProvideSamplesSubVo samplesSubVo) {

        if (StrUtil.isBlank(samplesSubVo.getId()) || StrUtil.isBlank(samplesSubVo.getMainId()) || StrUtil.isBlank(samplesSubVo.getPartnerId())) {
            return AjaxResult.error("获取不到参数！");
        }

        ProvideSamples provideSamples = provideSamplesService.getById(samplesSubVo.getMainId());
        if (provideSamples == null) {
            return AjaxResult.error("找不到样品发放活动！");
        }

        ProvideSamplesSub provideSamplesSub = getById(samplesSubVo.getId());
        if (provideSamplesSub == null) {
            return AjaxResult.error("找不到领取记录！");
        }

        if ("已回收".equals(provideSamplesSub.getOrderStatus())) {
            return AjaxResult.error("此用户名额已回收，无需重复操作！");
        }
        if ("已发货".equals(provideSamplesSub.getOrderStatus())) {
            return AjaxResult.error("已发货，不能回收名额！");
        }
        if ("已完成".equals(provideSamplesSub.getOrderStatus())) {
            return AjaxResult.error("订单已完成，不能回收名额！");
        }
        if ("已评价".equals(provideSamplesSub.getOrderStatus())) {
            return AjaxResult.error("订单已完成，不能回收名额！");
        }

        String refundNo = "";
        // 1.退还报名费用（大于0，才需要退）
        if(new BigDecimal(provideSamplesSub.getPayAmount()).compareTo(BigDecimal.ZERO) > 0){
            refundNo = wxPaySystemApi.samplesRefund(new BigDecimal(provideSamplesSub.getPayAmount()), "已回收", provideSamplesSub);
        }

        // 1.修改领取记录状态为“已回收”
        LambdaUpdateWrapper<ProvideSamplesSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProvideSamplesSub::getId, samplesSubVo.getId());
        updateWrapper.set(ProvideSamplesSub::getOrderStatus, "已回收");
        if(StrUtil.isNotBlank(refundNo)){
            updateWrapper.set(ProvideSamplesSub::getRefundNo, refundNo);
            updateWrapper.set(ProvideSamplesSub::getRefundTime, DateUtil.now());
            updateWrapper.set(ProvideSamplesSub::getRefundAmount, new BigDecimal(provideSamplesSub.getPayAmount()));
        }
        if (!update(updateWrapper)) {
            throw new ServiceException("修改领取记录状态为“已回收”出错了！");
        }

        // 2.释放名额；
        LambdaUpdateWrapper<ProvideSamples> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(ProvideSamples::getId, samplesSubVo.getMainId());
        wrapper.set(ProvideSamples::getRemainQuota, provideSamples.getRemainQuota() + 1);
        wrapper.set(ProvideSamples::getUpdateTime, DateUtil.now());
        if (!provideSamplesService.update(wrapper)) {
            throw new ServiceException("释放名额出错了！");
        }

        // 3.给参与者发放回收名额通知
        String first = "很抱歉，您的样品名额已回收，如有疑问请联系客服！";
        Provider provider = providerService.getByUserId(samplesSubVo.getPartnerId());
        if (provider != null) {
            first = "【区域服务商NO." + provider.getProviderId() + "】很抱歉，您的样品名额已回收，如有疑问请联系客服！";
        }
        HashMap<String, Object> params = new HashMap<>();
        params.put("first", first);
        params.put("keyword1", provideSamplesSub.getTaskNumber());// 订单编号
        params.put("keyword2", provideSamples.getGoodsName());// 商品名称
        params.put("remark", "点击查看商品详情。您所在区域发现不少潜在消费者，建议代理商品销售赚取佣金！（跳转到这款商品的商品销售详情，就是开团的那个详情，并非领取样品的商品详情！");
        params.put("pagepath", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + provideSamples.getGoodsNo() + "&goodsId=" + provideSamples.getGoodsId());// 跳转到商品销售详情
        params.put("pageurl", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + provideSamples.getGoodsNo() + "&goodsId=" + provideSamples.getGoodsId());// 跳转到商品销售详情
        params.put("docUnid", samplesSubVo.getId());
        params.put("userId", samplesSubVo.getPartnerId());
        Map<String, Object> data = new HashMap<>();
        data.put(NotifySendEnum.WX_PUBLIC_NUMBER.name(), params);
        applicationContext.publishEvent(new NotifySendEvent(this,
                NotifySendEnum.WX_PUBLIC_NUMBER,
                NotifySceneEnum.GOODS_DELIVERY,
                data));
        return AjaxResult.success("成功回收名额！");
    }

    /**
     * 获取领取样品记录详情
     *
     * @param id
     * @return
     */
    @Override
    public ProvideSamplesSub getReceiveDetails(String id) throws ParseException {

        ProvideSamplesSub provideSamplesSub = getById(id);

        if("已发货".equals(provideSamplesSub.getOrderStatus())){
            provideSamplesSub.setOrderStatus("待收货");
        }
        if("已完成".equals(provideSamplesSub.getOrderStatus())){
            provideSamplesSub.setOrderStatus("待评价");
        }

        /*// 需要进行数据处理
        if ("待发货".equals(provideSamplesSub.getOrderStatus())) {
            provideSamplesSub.setOrderStatus("已领取，等待平台发货");
        }

        if ("已发货".equals(provideSamplesSub.getOrderStatus())) {

            // 根据发货时间，计算10天后的自动收货日期
            String enddate = DateUtils.plusDay(10, provideSamplesSub.getDeliveryGoodsTime());

            // 获取今天日期
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = new Date();
            String nowDate = sdf.format(date);

            // 计算 距离自动收货还差几天
            int diffValue = DateUtils.daysBetween(nowDate, enddate);

            provideSamplesSub.setOrderStatus("平台已发货<br>还有" + diffValue + "天自动确认");
        }*/

        return provideSamplesSub;
    }

    /**
     * 获取领取样品记录列表
     *
     * @param vo
     * @return
     */
    @Override
    public List<ProvideSamplesSub> getListByVo(ProvideSamplesSubVo vo) {
        LambdaQueryWrapper<ProvideSamplesSub> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(vo.getMainId())) {
            wrapper.eq(ProvideSamplesSub::getMainId, vo.getMainId());
        }

        if (StrUtil.isNotBlank(vo.getSearchStr())) {
            wrapper.and(wrap -> wrap.like(ProvideSamplesSub::getGoodsNo, vo.getSearchStr())
                    .or().like(ProvideSamplesSub::getPartnerId, vo.getSearchStr())
                    .or().like(ProvideSamplesSub::getPartnerName, vo.getSearchStr())
                    .or().like(ProvideSamplesSub::getConsigneeName, vo.getSearchStr())
                    .or().like(ProvideSamplesSub::getConsigneePhoneNum, vo.getSearchStr())
                    .or().like(ProvideSamplesSub::getConsigneeAddress, vo.getSearchStr()));
        }
        wrapper.orderByDesc(ProvideSamplesSub::getCreateTime);
        return list(wrapper);
    }


    /**
     * 确认收货
     *
     * @param id            订单记录id
     * @param currentStatus 当前的订单状态
     * @param status        收货成功后的状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeOrderStatus(String id, String currentStatus, String status) {
        Optional.ofNullable(baseMapper.selectById(id))
                .orElseThrow(() -> new ServiceException("订单不存在"));
        LambdaUpdateWrapper<ProvideSamplesSub> updateWrapper = new LambdaUpdateWrapper<>();

        updateWrapper.eq(ProvideSamplesSub::getId, id);
        updateWrapper.eq(ProvideSamplesSub::getOrderStatus, currentStatus);

        updateWrapper.set(ProvideSamplesSub::getOrderStatus, status);
        updateWrapper.set(ProvideSamplesSub::getReceivingTime, DateUtil.now());// 确认收货时间

        this.update(updateWrapper);
    }

    /**
     * 保存试用反馈
     *
     * @param samplesSub
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveFeedbackContent(ProvideSamplesSub samplesSub) {
        if (StrUtil.isBlank(samplesSub.getId())) {
            return false;
        }
        LambdaUpdateWrapper<ProvideSamplesSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProvideSamplesSub::getId, samplesSub.getId());
        updateWrapper.set(ProvideSamplesSub::getFeedbackContent, samplesSub.getFeedbackContent());
        updateWrapper.set(ProvideSamplesSub::getFeedbackPictures, samplesSub.getFeedbackPictures());
        updateWrapper.set(ProvideSamplesSub::getSocialPlatformPictures, samplesSub.getSocialPlatformPictures());
        updateWrapper.set(ProvideSamplesSub::getOrderStatus, "已评价");
        if (!update(updateWrapper)) {
            throw new ServiceException("保存试用反馈内容出错了！");
        }

        return true;
    }

    /**
     * 获取未提交反馈的记录
     *
     * @param samplesSub
     * @return
     */
    @Override
    public ProvideSamplesSub getNoFeedback(ProvideSamplesSub samplesSub) {
        LambdaQueryWrapper<ProvideSamplesSub> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProvideSamplesSub::getPartnerId, samplesSub.getPartnerId());
        wrapper.eq(ProvideSamplesSub::getOrderStatus, "已完成");
        // wrapper.eq(ProvideSamplesSub::getFeedbackContent, "");
        wrapper.orderByAsc(ProvideSamplesSub::getDeliveryGoodsTime);// 收货时间升序
        wrapper.last(" limit 1");
        return getOne(wrapper);
    }

    /**
     * 评级
     *
     * @param samplesSub
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rating(ProvideSamplesSub samplesSub) {
        if (StrUtil.isBlank(samplesSub.getId()) || StrUtil.isBlank(samplesSub.getGrade())) {
            throw new ServiceException("获取不到参数！");
        }

        // 1. 修改等级、报酬
        LambdaUpdateWrapper<ProvideSamplesSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProvideSamplesSub::getId, samplesSub.getId());
        updateWrapper.set(ProvideSamplesSub::getGrade, samplesSub.getGrade());
        updateWrapper.set(ProvideSamplesSub::getReward, samplesSub.getReward());
        updateWrapper.set(ProvideSamplesSub::getCouponAmount, samplesSub.getCouponAmount());
        updateWrapper.set(ProvideSamplesSub::getCouponRange, samplesSub.getCouponRange());
        if (!update(updateWrapper)) {
            throw new ServiceException("修改等级出错了！");
        }

        double _reward = 0.0;
        double points = 0.0;
        ProvideSamplesSub sub = getById(samplesSub.getId());
        if (sub.getReward() == null || StrUtil.isBlank(samplesSub.getReward().toString()) || sub.getReward().compareTo(BigDecimal.ZERO) == 0) {
            System.out.println("样品评级奖励为0，无需发放奖励！记录id为：" + samplesSub.getId());
        } else {
            _reward = sub.getReward().doubleValue();
            points = _reward * 100.0;

            // 2.发放报酬
            // 调用积分系统：转入钱包
            JSONObject object1 = new JSONObject();
            object1.put("userId", sub.getPartnerId());
            object1.put("points", String.format("%.0f", points));// 保留0位小数
            object1.put("reason", sub.getGoodsName() + "样品评级报酬，共" + String.format("%.2f", _reward) + "元");
            object1.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
            object1 = getToken(object1);
            JSONObject resObj = subPayToWallet(object1);
            if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                throw new ServiceException("给消费者【" + sub.getPartnerName() + "(" + sub.getInitiatorId() + ")" + "】样品评级报酬失败！领取记录：" + sub.getId());
            }
        }

        // 获取样品活动详情
        LambdaQueryWrapper<ProvideSamples> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProvideSamples::getId, sub.getMainId());
        ProvideSamples provideSamples = provideSamplesService.getOne(wrapper);

        String couponName = "平台优惠券";// 优惠券名称
        String batchId = "";// 批次ID
        String useScope = "";// 适用范围
        BigDecimal couponAmount = new BigDecimal(0);// 优惠券金额

        if (BeanUtil.isNotEmpty(provideSamples)) {
            // A级
            if ("A".equals(samplesSub.getGrade())) {
                if (provideSamples.getLevelACouponAmount().compareTo(BigDecimal.ZERO) > 0) {
                    // 如果优惠券金额大于零，则发放优惠券
                    couponAmount = provideSamples.getLevelACouponAmount();// A级优惠券金额

                    // A级优惠券适用范围。0此商品；1全部商品
                    if ("0".equals(provideSamples.getLevelACouponRange())) {
                        couponName = provideSamples.getGoodsName() + "专属优惠券";
                        batchId = provideSamples.getGoodsId();
                        useScope = provideSamples.getGoodsId();
                    }
                }
            }

            // B级
            if ("B".equals(samplesSub.getGrade())) {
                if (provideSamples.getLevelBCouponAmount().compareTo(BigDecimal.ZERO) > 0) {
                    // 如果优惠券金额大于零，则发放优惠券
                    couponAmount = provideSamples.getLevelBCouponAmount();// A级优惠券金额

                    // A级优惠券适用范围。0此商品；1全部商品
                    if ("0".equals(provideSamples.getLevelBCouponRange())) {
                        couponName = provideSamples.getGoodsName() + "专属优惠券";
                        batchId = provideSamples.getGoodsId();
                        useScope = provideSamples.getGoodsId();
                    }
                }
            }

            // C级
            if ("C".equals(samplesSub.getGrade())) {
                if (provideSamples.getLevelCCouponAmount().compareTo(BigDecimal.ZERO) > 0) {
                    // 如果优惠券金额大于零，则发放优惠券
                    couponAmount = provideSamples.getLevelCCouponAmount();// A级优惠券金额

                    // A级优惠券适用范围。0此商品；1全部商品
                    if ("0".equals(provideSamples.getLevelCCouponRange())) {
                        couponName = provideSamples.getGoodsName() + "专属优惠券";
                        batchId = provideSamples.getGoodsId();
                        useScope = provideSamples.getGoodsId();
                    }
                }
            }

            // 如果优惠券金额大于零，则发放优惠券
            if (couponAmount.compareTo(BigDecimal.ZERO) > 0) {
                // 3.发放优惠券
                JSONObject object2 = new JSONObject();
                object2.put("couponName", couponName);// 优惠券名称
                object2.put("couponAmount", couponAmount);// 优惠券金额
                if (StrUtil.isNotBlank(batchId)) {
                    object2.put("batchId", batchId);// 批次ID
                }
                if (StrUtil.isNotBlank(useScope)) {
                    object2.put("useScope", useScope);// 适用范围
                }
                object2.put("userId", sub.getPartnerId());// 用户id
                object2 = getToken(object2);
                JSONObject resObj2 = sendCoupon(object2);
                if (resObj2.isEmpty() || !"200".equals(resObj2.getString("code"))) {
                    throw new ServiceException("给消费者【" + sub.getPartnerName() + "(" + sub.getPartnerId() + ")" + "】发放优惠券失败！领取记录：" + sub.getId());
                }
            }
        }
        return true;
    }

    /** ********************************* 以下是定时任务 start lys ****************************************** */

    /**
     * 样品已签收后，发送反馈通知
     * <p>
     * 每天08:30分执行一次
     *
     * @return
     */
//    @Scheduled(cron = "${sample.send_feedback_msg.cron}")
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean sendFeedbackMsg() {

        log.info("********************************");
        log.info("开始执行定时任务：样品已签收后发送反馈通知....");

        // 获取已签收的领取记录
        MPJLambdaWrapper<ProvideSamplesSub> wrapper = new MPJLambdaWrapper<ProvideSamplesSub>()
                .selectAll(ProvideSamplesSub.class)
                .leftJoin(LogisticsInfo.class, LogisticsInfo::getModuleId, ProvideSamplesSub::getId)
                .eq(ProvideSamplesSub::getEnableFeedback, "1")// 表示开启反馈
                .eq(ProvideSamplesSub::getSendFeedback, "false")// 表示未发送反馈通知
                .eq(LogisticsInfo::getStatus, 3)// 表示已签收
                .eq(LogisticsInfo::getModule, "samples_module");// 表示样品发放的

        List<ProvideSamplesSub> list = list(wrapper);
        if (list == null || list.size() < 1) {
            log.info("没有已签收的领取记录，不需要发送反馈通知！");
        }

        for (ProvideSamplesSub samplesSub : list) {

            // 1.发送反馈通知
            HashMap<String, Object> params = new HashMap<>();
            params.put("first", "样品试用反馈！");
            params.put("keyword1", samplesSub.getTaskNumber());// 订单编号
            params.put("keyword2", samplesSub.getGoodsName());// 商品名称
            params.put("remark", "点击查看。");
            params.put("pagepath", "/pages_private_scene2/provide_samples/trial_feedback?recordId=" + samplesSub.getId());// （链接到【试用反馈】）
            params.put("pageurl", "/pages_private_scene2/provide_samples/trial_feedback?recordId=" + samplesSub.getId());// （链接到【试用反馈】）
            params.put("docUnid", samplesSub.getId());
            params.put("userId", samplesSub.getPartnerId());
            JSONObject object = sendMsg(params);
            if (object.isEmpty() || !"200".equals(object.getString("code"))) {
                log.error("给消费者【" + samplesSub.getPartnerName() + "(" + samplesSub.getPartnerId() + ")" + "】发送反馈通知失败！");
                log.error("执行结束！");
                log.info("********************************");
                return false;
            }

            // 2.修改状态
            LambdaUpdateWrapper<ProvideSamplesSub> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ProvideSamplesSub::getId, samplesSub.getId());
            updateWrapper.set(ProvideSamplesSub::getSendFeedback, "true");
            updateWrapper.set(ProvideSamplesSub::getLogisticsStatus, "签收");
            if (!update(updateWrapper)) {
                log.error("修改状态出错了，出错记录id：" + samplesSub.getId() + "。");
                log.info("执行结束（出错中断）。");
                log.info("********************************");
                return false;
            }
        }

        log.info("执行成功！");
        log.info("********************************");
        return true;
    }

    /**
     * 发送订单通知
     *
     * @param params 实例对象
     * @return
     */
    public JSONObject sendMsg(HashMap<String, Object> params) {
        JSONObject obj = new JSONObject();
        params.put("appid", msgAppid);
        params.put("wf_num", msgWfNum);
        HttpResponse resp = HttpRequest.post(bpmUrl)
                .header("sysid", sysId)
                .header("syspwd", sysPwd)
                .header("userId", "admin")
                .form(params)
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /** ********************************* 以上是定时任务 end lys ****************************************** */

    /**
     * 分页查询
     *
     * @param vo
     * @return
     */
    @Override
    public List<ProvideSamplesSub> findListByVo(ProvideSamplesSubVo vo) {
        List<ProvideSamplesSub> list = baseMapper.selectList(buildSamplesSubWrapper(vo, true));
        for (ProvideSamplesSub ps : list) {
            if (StrUtil.isNotBlank(ps.getConsigneeAddress())) {
                /*
                // 收货地址（去掉居委会）
                例子：广东省-广州市-天河区-天园街道-科韵社区居委会 655号
                改成：广东省-广州市-天河区-天园街道 655号*/
                String[] arr = ps.getConsigneeAddress().split(" ");
                String[] arrRegion = arr[0].split("-");
                // 新的地址格式
                ps.setConsigneeAddress(arrRegion[0] + "-" + arrRegion[1] + "-" + arrRegion[2] + "-" + arrRegion[3] + " " + arr[1]);
            }
        }

        return list;
    }

    private LambdaQueryWrapper<ProvideSamplesSub> buildSamplesSubWrapper(ProvideSamplesSubVo vo, boolean isSort) {
        LambdaQueryWrapper<ProvideSamplesSub> queryWrapper = new LambdaQueryWrapper<>();

        if (StringUtils.isNotBlank(vo.getMainId())) {
            queryWrapper.eq(ProvideSamplesSub::getMainId, vo.getMainId());
        }
        if (StringUtils.isNotBlank(vo.getPartnerId())) {
            queryWrapper.eq(ProvideSamplesSub::getPartnerId, vo.getPartnerId());
        }
        if (StringUtils.isNotBlank(vo.getOrderStatus())) {
            queryWrapper.eq(ProvideSamplesSub::getOrderStatus, vo.getOrderStatus());
        }
        if (StringUtils.isNotBlank(vo.getConsigneeName())) {
            queryWrapper.like(ProvideSamplesSub::getConsigneeName, vo.getConsigneeName());
        }
        if (StringUtils.isNotBlank(vo.getConsigneePhonenum())) {
            queryWrapper.like(ProvideSamplesSub::getConsigneePhoneNum, vo.getConsigneePhonenum());
        }
        if (isSort) {
            queryWrapper.orderByDesc(ProvideSamplesSub::getCreateTime);
        }
        return queryWrapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void logisticsChangeNotify(@NonNull ProvideSamplesSub samplesSub, String action) {
        if (samplesSub == null) {
            throw new ServiceException("数据异常");
        }
        // 发送物流更新通知内容
        String first = CommonConstants.LOGISTICS.CHANGE_LOGISTICS_ACTION.equals(action) ? "亲，很抱歉，您购买的宝贝物流单号已变更为：" + samplesSub.getCourierName() + " " + samplesSub.getCourierNumber() + "，请知晓！"
                : "亲，您的样品已发货！物流单号：" + samplesSub.getCourierName() + " " + samplesSub.getCourierNumber();
        HashMap<String, Object> params = new HashMap<>();
        params.put("first", first);
        params.put("keyword1", samplesSub.getTaskNumber());// 订单编号
        params.put("keyword2", samplesSub.getGoodsName());// 商品名称
        params.put("remark", "点击查看订单详情");
        params.put("pagepath", "/pages_private_scene2/provide_samples/order_details?recordId=" + samplesSub.getId());// （链接到【订单详情】）
        params.put("pageurl", "/pages_private_scene2/provide_samples/order_details?recordId=" + samplesSub.getId());// （链接到【订单详情】）
        params.put("docUnid", samplesSub.getId());
        params.put("userId", samplesSub.getPartnerId());
        // 组建通知数据
        Map<String, Object> data = new HashMap<>();
        data.put(NotifySendEnum.WX_PUBLIC_NUMBER.name(), params);
        data.put(NotifySendEnum.SMS.name(), GoodsDeliveryNoticeVo.builder()
                .sendTo(samplesSub.getConsigneeName())
                .phoneNumber(samplesSub.getConsigneePhoneNum())
                .commodity(samplesSub.getGoodsName())
                .company(samplesSub.getCourierName())
                .numbers(samplesSub.getCourierNumber())
                .build());
        try {
            applicationContext.publishEvent(new NotifySendEvent(this,
                    NotifySendEnum.ALL,
                    NotifySceneEnum.GOODS_DELIVERY,
                    data));
        } catch (Exception e) {
            // 通知失败是可以忍受的
            log.error("发送商品通知失败");
        }
    }

    /**
     * 修改收货信息
     *
     * @param provideSamplesSub
     * @return
     */
    @Override
    public AjaxResult modifyReceivingInfo(ProvideSamplesSub provideSamplesSub) {
        if (StrUtil.isBlank(provideSamplesSub.getId())) {
            return AjaxResult.error("获取不到记录id！");
        }

        LambdaUpdateWrapper<ProvideSamplesSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProvideSamplesSub::getId, provideSamplesSub.getId());

        updateWrapper.set(ProvideSamplesSub::getConsigneeName, provideSamplesSub.getConsigneeName());
        updateWrapper.set(ProvideSamplesSub::getConsigneePhoneNum, provideSamplesSub.getConsigneePhoneNum());
        updateWrapper.set(ProvideSamplesSub::getConsigneeAddress, provideSamplesSub.getConsigneeAddress());
        updateWrapper.set(ProvideSamplesSub::getUpdateTime, DateUtil.now());

        if (!update(updateWrapper)) {
            throw new ServiceException("修改收货信息出错了！");
        }

        return AjaxResult.success("修改收货信息成功！");
    }

    /**
     * 判断用户的收货信息是否填写完成
     *
     * @param samplesSub
     * @return
     */
    private String verifyReceiptInfo(ProvideSamplesSub samplesSub) {
        if (StringUtils.isBlank(samplesSub.getConsigneeName())) {
            return "收货人姓名未填写";
        }
        if (StringUtils.isBlank(samplesSub.getConsigneePhoneNum())) {
            return "收货人手机号码未填写";
        }
        if (StringUtils.isBlank(samplesSub.getConsigneeAddress())) {
            return "收货地址未填写";
        }
        return "";
    }

    /** ********************* 以下调用其他系统的 ******************************* */

    /**
     * 获取token与authstr
     *
     * @param
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject getToken(JSONObject object) {
        HttpResponse resp = HttpRequest.post(getOrderSysTokenUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            JSONObject obj = JSON.parseObject(resp.body());
            String token = obj.getString("data");
            String tmpStr = authSalt.charAt(2) + authSalt.charAt(8) + token + authSalt.charAt(10) + authSalt.charAt(5);
            object.put("token", token);
            object.put("authStr", SecureUtil.md5(tmpStr));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return object;
    }

    /**
     * 积分系统：保存记录到订单系统
     *
     * @return
     */
    public JSONObject saveRecord2OrderSys(JSONObject object) {
        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(addOrderUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 积分系统：转入钱包
     *
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject subPayToWallet(JSONObject object) {
        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(subPayToWallet)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 积分系统：减扣钱包余额
     *
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject deduction(JSONObject object) {

        System.out.println("********积分系统：减扣钱包余额*********");
        System.out.println("deductUrl=" + deductUrl);
        System.out.println("参数object=" + object);

        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(deductUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        System.out.println("返回结果=" + resp.body());
        System.out.println("*****************");
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 优惠券系统：发放优惠券
     *
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject sendCoupon(JSONObject object) {
        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(createAndIssueUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }


    @Override
    public void businessStatusFinish(String id) {
        if (StringUtils.isBlank(id)) {
            throw new ServiceException("数据不存在");
        }
        LambdaUpdateWrapper<ProvideSamplesSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(ProvideSamplesSub::getReceivingTime, DateUtils.getNow());
        updateWrapper.set(ProvideSamplesSub::getOrderStatus, "已完成");
        updateWrapper.eq(ProvideSamplesSub::getId, id);
        update(updateWrapper);
    }


    @Override
    public Map<String, Object> indicatorQuery(String mainId) {
        return baseMapper.indicatorQuery(mainId);
    }

    @Override
    public List<MaterialDownloadDTO> generateTrialMaterialDirectory(String mainId) {
        List<ProvideSamplesSub> samplesSubs = getGradeListByMainId(mainId);
        if (samplesSubs.isEmpty()) {
            return null;
        }
        List<MaterialDownloadDTO> materialDownloadDTOS = samplesSubs.parallelStream().map(item -> {
            MaterialDownloadDTO materialDownloadDTO = MaterialDownloadDTO.builder()
                    .fileType((short) 0)
                    .fileName(item.getPartnerName() + "(样品试用报告)")
                    .build();
            List<MaterialDownloadDTO> children = new ArrayList<>();
            if (StringUtils.isNotBlank(item.getFeedbackPictures())) {
                // 试用反馈图片
                MaterialDownloadDTO feedbackDirectory = MaterialDownloadDTO.builder()
                        .fileType((short) 0)
                        .fileName("试用反馈图片")
                        .build();
                List<MaterialDownloadDTO> feedbackMaterialList = new ArrayList<>();
                String[] feedbackPictures = item.getFeedbackPictures().split(",");
                for (String feedbackPicture : feedbackPictures) {
                    feedbackMaterialList.add(MaterialDownloadDTO.builder()
                            .fileType((short) 1)
                            .fileName(FileUtil.getName(feedbackPicture))
                            .downloadUrl(feedbackPicture)
                            .build());
                }
                feedbackDirectory.setChildren(feedbackMaterialList);
                children.add(feedbackDirectory);
            }
            if (StringUtils.isNotBlank(item.getSocialPlatformPictures())) {
                // 社交平台凭证
                MaterialDownloadDTO socialPlatformDirectory = MaterialDownloadDTO.builder()
                        .fileType((short) 0)
                        .fileName("社交平台凭证")
                        .build();
                List<MaterialDownloadDTO> socialPlatformList = new ArrayList<>();
                String[] socialPlatformPictures = item.getSocialPlatformPictures().split(",");
                for (String socialPlatformPicture : socialPlatformPictures) {
                    socialPlatformList.add(MaterialDownloadDTO.builder()
                            .fileType((short) 1)
                            .fileName(FileUtil.getName(socialPlatformPicture))
                            .downloadUrl(socialPlatformPicture)
                            .build());
                }
                socialPlatformDirectory.setChildren(socialPlatformList);
                children.add(socialPlatformDirectory);
            }
            materialDownloadDTO.setChildren(children);
            return materialDownloadDTO;
        }).collect(Collectors.toList());
        // 生成excel导出文件
        List<ProvideSamplesSubDTOFactory.ExportEvaluationDTO> exportDTOList = samplesSubs.stream()
                .map(item -> provideSamplesSubDTOFactory.toExportEvaluationDTO.apply(item))
                .collect(Collectors.toList());
        ExcelUtil<ProvideSamplesSubDTOFactory.ExportEvaluationDTO> util = new ExcelUtil<>(ProvideSamplesSubDTOFactory.ExportEvaluationDTO.class);
        InputStream inputStream = util.exportExcel(exportDTOList);
        String path = cosUpload.uploadFile(inputStream, "样品领取记录.xlsx", true);
        materialDownloadDTOS.add(MaterialDownloadDTO.builder()
                .fileType((short) 1)
                .fileName(FileUtil.getName(path))
                .downloadUrl(path)
                .build());
        return materialDownloadDTOS;
    }

    @Override
    public List<ProvideSamplesSub> getListByMainId(String mainId) {
        return baseMapper.selectList(new LambdaQueryWrapper<ProvideSamplesSub>()
                .eq(ProvideSamplesSub::getMainId, mainId));
    }

    @Override
    public List<ProvideSamplesSub> getGradeListByMainId(String mainId) {
        return baseMapper.selectList(new LambdaQueryWrapper<ProvideSamplesSub>()
                .eq(ProvideSamplesSub::getMainId, mainId).ne(ProvideSamplesSub::getGrade, ""));
    }
}